import { Folder } from './Folder';
import { RegexHelper } from './Helpers/RegexHelper';
import { ResponseParser } from './Helpers/ResponseParser';
import { StringHelper } from './Helpers/StringHelper';
import { UTF7 } from './Helpers/UTF7';
import { Client } from './Client';
import { Properties } from './Properties';
import { Response, ResponseType } from './Response';

export class Store {
  private properties: Properties;
  private client: Client;
  private folders: Folder[];

  public constructor(properties: Properties) {
    this.properties = properties;
    this.client = new Client();
    this.folders = [];
  }

  // 必要时可拿出 Client 对象发送命令
  public getClient() {
    return this.client;
  }

  // 必要时可直接拿出 MailSocket 对象发送消息
  public getMailSocket() {
    return this.client.getMailSocket();
  }

  // 必要时可直接拿出最底层的 socket 对象
  public getSocket() {
    return this.client.getMailSocket().getSocket();
  }

  // 关闭
  public close() {
    this.client.close();
  }

  /**
   * 登录鉴权
   * @param cmdUse 命令列表 连接前的命令,如果有需要直接上传即可
   * @returns 
   */
  public connect(cmdUse: string[]=[]) {
    return new Promise<void>(async (resolve, reject) => {
      const connectRes = await this.client.connect(this.properties.getHost(), this.properties.getPort(), this.properties.getTLS());
      // 连接失败
      if (!connectRes.ok) {
        reject(Response(201, 'store:connect error', connectRes.error));
      } else {
        // 向外暴露连接前的的命令
        for (const cmd of cmdUse) {
          await this.client.sendCommand(cmd);
        }
        // 网易系列需要发送id, 
        // await this.client.sendCommand(`ID ("id" "1")`);
        // 连接成功，开始登陆
        const loginRes = await this.client.sendCommand(
          `LOGIN ${this.properties.getFrom()} ${this.properties.getAuthCode()}`
        );
        // 服务器返回ok
        if (loginRes.ok) {
          resolve();
        } else {
          // 服务器返回登陆有误
          reject(Response(202, 'store:login error', loginRes.error));
        }
      }
    });
  }

  // 获取所有文件夹
  public getFolders() {
    return new Promise<readonly Folder[]>(async (resolve, reject) => {
      const response = await this.client.sendCommand(`LIST "" "*"`);
      // 失败
      if (!response.ok) {
        response.msg = 'store:getFolders error';
        reject(response);
      } else {
        // 成功
        const { payload } = response;
        const folderNames = ResponseParser.matchAllFolders(payload);
        const Folders: Folder[] = [];
        folderNames.forEach((name) => {
          const folder = new Folder(this, UTF7.imapDecode(name));
          Folders.push(folder);
        });
        resolve(Folders);
      }
    });
  }

  // 根据文件夹名称获取文件夹对象
  public getFolder(name: string) {
    return new Promise<Folder>(async (resolve, reject) => {
      const folders = await this.getFolders();
      const target = folders.find((folder) => {
        return folder.getName() === name;
      });
      if (target) {
        resolve(target);
      } else {
        reject(Response(204, `store:getFolder error, can't find folder,name:${name}`, new Error('Folder not found')));
      }
    });
  }

  // 获取服务器支持的能力
  public getCapAbility() {
    return new Promise<string[]>(async (resolve, reject) => {
      const response = await this.client.sendCommand(`CAPABILITY`);
      if (!response.ok) {
        response.error.message = 'store:getCapAbility error';
        reject(response.error);
      } else {
        const matches = RegexHelper.matchAll(response.payload, /\*\sCAPABILITY\s(.*)/gim);
        const abilities: string[] = [];
        matches.forEach((match) => {
          abilities.push(...match[1].split(' '));
        });
        resolve(abilities);
      }
    });
  }
}
